/**
 * @file    elog_buf.c
 * @brief   EasyLogger缓冲输出模块实现文件
 * @details 本文件实现了EasyLogger的缓冲输出功能，包括：
 *          - 基于固定大小缓冲区的日志缓存
 *          - 缓冲区满时的自动刷新机制
 *          - 缓冲输出模式的启用和禁用控制
 *          - 手动刷新缓冲区接口
 */

#include <elog.h>
#include <string.h>

#ifdef ELOG_BUF_OUTPUT_ENABLE
#if !defined(ELOG_BUF_OUTPUT_BUF_SIZE)
    #error "Please configure buffer size for buffered output mode (in elog_cfg.h)"
#endif

/* ---------------------------------------------- 缓冲输出模式变量 ------------------------------------------ */
static char log_buf[ELOG_BUF_OUTPUT_BUF_SIZE] = { 0 };                      /* 缓冲输出模式的缓冲区 */
static size_t buf_write_size = 0;                                           /* 日志缓冲区当前写入大小 */
static bool is_enabled = false;                                             /* 缓冲输出模式启用标志 */

extern void elog_port_output(const char *log, size_t size);
extern void elog_output_lock(void);
extern void elog_output_unlock(void);

/* ---------------------------------------------- 缓冲输出函数 ---------------------------------------------- */
/**
 * @brief  缓冲区满时输出缓冲的日志
 * @param  log 待缓冲的日志行内容
 * @param  size 日志大小
 * @note   当缓冲区空间不足时，会先输出已缓冲的内容，然后继续缓冲新日志
 */
void elog_buf_output(const char *log, size_t size)
{
    size_t write_size = 0, write_index = 0;                                 /* 写入大小和写入索引 */

    if (!is_enabled)
    {
        elog_port_output(log, size);                                        /* 未启用缓冲模式，直接输出 */
        return;
    }

    while (true)
    {
        if (buf_write_size + size > ELOG_BUF_OUTPUT_BUF_SIZE)
        {
            write_size = ELOG_BUF_OUTPUT_BUF_SIZE - buf_write_size;         /* 计算剩余可写入大小 */
            memcpy(log_buf + buf_write_size, log + write_index, write_size);/* 填满缓冲区 */
            write_index += write_size;                                      /* 更新写入索引 */
            size -= write_size;                                             /* 更新剩余大小 */
            /* 输出满缓冲区的日志 */
            elog_port_output(log_buf, ELOG_BUF_OUTPUT_BUF_SIZE);
            /* 重置写入索引 */
            buf_write_size = 0;
        }
        else
        {
            memcpy(log_buf + buf_write_size, log + write_index, size);      /* 将剩余日志写入缓冲区 */
            buf_write_size += size;                                         /* 更新缓冲区写入大小 */
            break;                                                          /* 完成写入，退出循环 */
        }
    }
}

/**
 * @brief  将所有缓冲的日志刷新到输出设备
 * @note   此函数会立即输出缓冲区中的所有日志内容
 */
void elog_flush(void)
{
    if (buf_write_size == 0)
    {
        return;                                                             /* 缓冲区为空，无需刷新 */
    }
    /* 锁定输出 */
    elog_output_lock();
    /* 输出缓冲区中的日志 */
    elog_port_output(log_buf, buf_write_size);
    /* 重置写入索引 */
    buf_write_size = 0;
    /* 解锁输出 */
    elog_output_unlock();
}

/**
 * @brief  启用或禁用缓冲输出模式
 * @param  enabled true: 启用, false: 禁用
 * @note   禁用模式时，日志将直接输出而不经过缓冲
 */
void elog_buf_enabled(bool enabled)
{
    is_enabled = enabled;                                                   /* 设置缓冲模式启用状态 */
}
#endif /* ELOG_BUF_OUTPUT_ENABLE */
